﻿// CNodeDlg.cpp: 实现文件
//

#include "pch.h"
#include "CClient.h"
#include "CNodeDlg.h"
#include "afxdialogex.h"
#include "CGotoDlg.h"


// CNodeDlg 对话框

int UM_NOTIFY = WM_USER + 3301;

// 1. 注册查找替换对话框消息
UINT WM_FINDREPLACE = RegisterWindowMessage(FINDMSGSTRING);

IMPLEMENT_DYNAMIC(CNodeDlg, CDialog)

CNodeDlg::CNodeDlg(CWnd* pParent /*=nullptr*/)
	: CDialog(IDD_NODE, pParent)
{

}

CNodeDlg::~CNodeDlg()
{
}

void CNodeDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT, m_edit);
}


BEGIN_MESSAGE_MAP(CNodeDlg, CDialog)
	ON_WM_SIZE()
	ON_COMMAND(ID_FILE_EXIT, &CNodeDlg::OnFileExit)
	ON_WM_DESTROY()
	ON_WM_SETCURSOR()
	ON_WM_SYSCOMMAND()
	ON_WM_CLOSE()
	ON_COMMAND(ID_FILE_NEW, &CNodeDlg::OnFileNew)
	ON_COMMAND(ID_FILE_NEW_DLG, &CNodeDlg::OnFileNewDlg)
	ON_COMMAND(ID_FILE_SAVE_AS, &CNodeDlg::OnFileSaveAs)
	ON_COMMAND(ID_FILE_OPEN, &CNodeDlg::OnFileOpen)
	ON_COMMAND(ID_FILE_SAVE, &CNodeDlg::OnFileSave)
	ON_COMMAND(ID_FILE_SET, &CNodeDlg::OnFileSet)
	ON_COMMAND(ID_FILE_PRINT, &CNodeDlg::OnFilePrint)
	ON_MESSAGE(UM_NOTIFY, &CNodeDlg::OnUmNotify)
	ON_COMMAND(ID_EDIT_SELECT_ALL, &CNodeDlg::OnEditSelectAll)
	ON_COMMAND(ID_EDIT_GOTO, &CNodeDlg::OnEditGoto)
	ON_COMMAND(ID_EDIT_UNDO, &CNodeDlg::OnEditUndo)
	ON_COMMAND(ID_EDIT_COPY, &CNodeDlg::OnEditCopy)
	ON_COMMAND(ID_EDIT_CUT, &CNodeDlg::OnEditCut)
	ON_COMMAND(ID_EDIT_PASTE, &CNodeDlg::OnEditPaste)
	ON_COMMAND(ID_EDIT_DEL, &CNodeDlg::OnEditDel)
	ON_WM_DROPFILES()
	ON_COMMAND(ID_EDIT_SEARCH, &CNodeDlg::OnEditSearch)
	ON_COMMAND(ID_EDIT_FIND, &CNodeDlg::OnEditFind)
	ON_COMMAND(ID_EDIT_NEXT, &CNodeDlg::OnEditNext)
	ON_COMMAND(ID_EDIT_PREV, &CNodeDlg::OnEditPrev)
	ON_COMMAND(ID_EDIT_REPLACE, &CNodeDlg::OnEditReplace)
	ON_COMMAND(ID_EDIT_DATE, &CNodeDlg::OnEditDate)
	ON_COMMAND(ID_FORMAT_FONT, &CNodeDlg::OnFormatFont)
	ON_COMMAND(ID_FORMAT_TEXT, &CNodeDlg::OnFormatText)
	ON_COMMAND(ID_FORMAT_BACK, &CNodeDlg::OnFormatBack)

	// 2. 查找替换对话框消息回调函数
	ON_REGISTERED_MESSAGE(WM_FINDREPLACE, &CNodeDlg::OnFindReplace)
	ON_WM_CTLCOLOR()
	ON_COMMAND(ID_FORMAT_WRAP, &CNodeDlg::OnFormatWrap)
END_MESSAGE_MAP()


// CNodeDlg 消息处理程序


void CNodeDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);
	CWnd* pEdit = GetDlgItem(IDC_EDIT);
	if (pEdit != nullptr) {
		pEdit->MoveWindow(0, 0, cx, cy, FALSE);// 自适应宽高，FALSE 不重绘
	}
}


BOOL CNodeDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	// RichEdit 需要初始化，否则包含的对话框无法弹出
	AfxInitRichEdit2();

	UpdateTitle();

	// 设置edit最大长度
	int n = m_edit.GetLimitText();
	m_edit.SetLimitText(n * 100);

	// 或通过资源属性配置
	/*CMenu menu;
	menu.LoadMenu(IDR_MENU);
	SetMenu(&menu);*/

	// 获取系统菜单
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr) {
		pSysMenu->AppendMenu(MF_SEPARATOR);// 间隔线
		// 鼠标菜单栏右击显示
		// 编号 名称
		pSysMenu->AppendMenu(MF_STRING, 123012, _T("自添加项"));
		// 接收系统菜单消息，类向导->消息->SYSCOMMAND OnSysCommand()
	}

	HICON hIcon = theApp.LoadIcon(IDR_MAINFRAME);
	SetIcon(hIcon, FALSE);
	// 1. 加载快捷键资源 2. 添加虚函数PreTranslateMessage
	m_hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));

	// 读取注册表，恢复退出时位置
	/*LPRECT p = NULL;
	UINT size = 0;
	BOOL b = theApp.GetProfileBinary(_T("SETTING"), _T("RECT"), (LPBYTE*)&p, &size);
	if (b) {
		MoveWindow(p, FALSE);
		delete[] p;
	}*/
	// 另一种读法
	CRect wr;
	wr.left = theApp.GetProfileInt(_T("RECT"), _T("LEFT"), 0);
	wr.top = theApp.GetProfileInt(_T("RECT"), _T("TOP"), 0);
	wr.right = theApp.GetProfileInt(_T("RECT"), _T("RIGHT"), 800);
	wr.bottom = theApp.GetProfileInt(_T("RECT"), _T("BOTTOM"), 600);
	MoveWindow(wr, FALSE);

	CRect rect;
	GetClientRect(rect);
	CWnd* pEdit = GetDlgItem(IDC_EDIT);
	if (pEdit != nullptr) {
		pEdit->MoveWindow(rect, FALSE);// 自适应宽高，FALSE 不重绘
	}

	// 光标的设置
	// 第一个参数为NULL，则从系统加载
	// auto hCursor = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_PERSON));
	// auto hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_PERSON));
	// 在MouseMove时使用才生效，消息被拦，通过OnSetCursor函数
	// SetCursor(hCursor);

	// 图标放入托盘
	NOTIFYICONDATA nd;
	nd.cbSize = sizeof(NOTIFYICONDATA);
	nd.hWnd = GetSafeHwnd();
	nd.uID = IDR_MAINFRAME;
	nd.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
	nd.uCallbackMessage = UM_NOTIFY;// 用户消息
	nd.hIcon = hIcon;
	_tcscpy_s(nd.szTip, _countof(nd.szTip), _T("记事本"));
	Shell_NotifyIcon(NIM_ADD, &nd);

	LoadFont();

	return TRUE;
}

void CNodeDlg::LoadFont()
{
	// 启动时加载配置文件中的字体信息
	LPLOGFONT p = nullptr;
	UINT nLen = sizeof(LOGFONT);
	theApp.GetProfileBinary(_T("SETTING"), _T("FONT"), (LPBYTE*)&p, &nLen);
	if (p) {
		m_font.DeleteObject();
		m_font.CreateFontIndirect(p);
		m_edit.SetFont(&m_font, FALSE);
		delete p;
	}
	// 背景色
	m_clText = theApp.GetProfileInt(_T("SETTING"), _T("TEXT_COLOR"), 0x000000);
	m_clBlack = theApp.GetProfileInt(_T("SETTING"), _T("BACK_COLOR"), 0xffffff);
	// 更新画刷
	m_brush.DeleteObject();
	m_brush.CreateSolidBrush(m_clBlack);
}


void CNodeDlg::OnOK()
{
	// TODO: 在此添加专用代码和/或调用基类

	CDialog::OnOK();
}


void CNodeDlg::OnCancel()
{
	// TODO: 在此添加专用代码和/或调用基类

	CDialog::OnCancel();
}

// 窗口销毁回调，句柄仍然可用，与OnInitDialog是一对
void CNodeDlg::OnDestroy()
{
	CDialog::OnDestroy();
	if (!IsIconic()) {// 非最小化托盘时才记录位置 GetStyle() & WM_MINIMIZE
		CRect rect;
		GetWindowRect(rect);
		// 写入注册表
		theApp.WriteProfileBinary(_T("SETTING"), _T("RECT"), (LPBYTE)&rect, sizeof(CRect));

		theApp.WriteProfileInt(_T("RECT"), _T("LEFT"), rect.left);
		theApp.WriteProfileInt(_T("RECT"), _T("TOP"), rect.top);
		theApp.WriteProfileInt(_T("RECT"), _T("RIGHT"), rect.right);
		theApp.WriteProfileInt(_T("RECT"), _T("BOTTOM"), rect.bottom);

		// 写字符串
		theApp.WriteProfileString(_T("PRO"), _T("KEY"), _T("写入的字符串"));
	}

	// 图标移除托盘
	NOTIFYICONDATA nd;
	nd.cbSize = sizeof(NOTIFYICONDATA);
	nd.hWnd = GetSafeHwnd();
	nd.uID = IDR_MAINFRAME; // 编号，多个图标时
	Shell_NotifyIcon(NIM_DELETE, &nd);

	// 加载exe传参
	CString cmd = theApp.m_lpCmdLine;
}

void CNodeDlg::PostNcDestroy()
{
	// 非模式对话框时，比OnDestroy还要晚
	CDialog::PostNcDestroy();// 这个默认里面空执行
	// delete this; 如果当前Dlg对象是new出来的需要加上这行
}

// 默认全局：framework.h -> afxwin.h -> afx.h -> afxver_.h -> afxv_w32.h -> Windows.h -> winuser.h/winbase.h/windef.h
// theApp: afxwin.h -> CWinApp
BOOL CNodeDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	//auto hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	//// 系统光标不需要 MAKEINTRESOURCE 已经int转resource了 
	//// auto hCursor = LoadCursor(NULL, IDC_ARROW);
	//// 通用已经自动转了
	//hCursor = theApp.LoadCursor(IDC_HAND);
	//// 只支持系统光标
	//theApp.LoadStandardCursor(IDC_HAND);
	//// 在MouseMove时使用才生效，消息被拦，通过OnSetCursor函数
	//SetCursor(hCursor);
	//return TRUE;
	return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

// 系统菜单消息回调
void CNodeDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if (nID == 123012) {
		// AfxMessageBox(_T("自定义菜单"));
		CWnd* p = FindWindow(_T("Notepad"), NULL);
		if (p) {
			//p->BringWindowToTop();// 顶层显示
			p->SetForegroundWindow();// 激活显示 和上面差不多效果
			p->FlashWindow(FALSE);// 闪烁
		}
	}

	switch (nID) {
	case SC_MINIMIZE:// 最小化时直接隐藏
		ShowWindow(SW_HIDE);// 隐藏
		return;
	case SC_CLOSE:// 右上角关闭按钮系统消息
		// ShowWindow(SW_MINIMIZE);// 关闭时最小化
		// ShowWindow(SW_HIDE);// 隐藏
		OnFileExit();// 汇总到菜单处理
		return;
	}

	CDialog::OnSysCommand(nID, lParam);
}


// WM_CLOSE 消息
void CNodeDlg::OnClose()
{
	// 可以注掉ON_WM_SYSCOMMAND()
	// 右上角关闭按钮系统消息 OnSysCommand拦截这里不会进来
	CDialog::OnClose();
}


void CNodeDlg::OnFileNew()
{
	if (Prompt()) {
		m_sFile = _T("");
		m_edit.SetWindowText(_T(""));
		UpdateTitle();
	}
}

// 打开新窗口
void CNodeDlg::OnFileNewDlg()
{
	TCHAR s[MAX_PATH];
	if (GetModuleFileName(theApp.m_hInstance, s, _countof(s)) == 0) {
		AfxMessageBox(_T("创建失败"));
		return;
	}
	// 3种启动函数
	// _tsystem(s);// 启动 只用于控制台程序
	CString str = s;
	// str += _T(" D:\\1.txt");
	// WinExec(_bstr_t(s), SW_SHOWNORMAL);
	// WinExec(_bstr_t(str), SW_SHOWNORMAL);
	// 等价双击
	// 父窗口 默认打开方式 打开的文件  参数  D:\\可以作为目录放后一个参数中
	ShellExecute(NULL, _T("open"), str, _T(" D:\\1.txt"), NULL, SW_SHOWNORMAL);
}

void CNodeDlg::OnFileSaveAs()
{
	// OFN_OVERWRITEPROMPT 有文件存在 提示
	// 派生CFileDialog需要bVistaStyle为FALSE，否则init函数不能进入
	CFileDialog dlg(FALSE, _T("txt"), _T("E:\\"), OFN_OVERWRITEPROMPT, szFilter);// FALSE 另存为
	
	// 添加自定义的控件
	enum { IDC_COMBO  = 0x301};
	dlg.AddComboBox(IDC_COMBO);
	dlg.AddControlItem(IDC_COMBO, 0, _T("ANSI"));
	dlg.AddControlItem(IDC_COMBO, 1, _T("UTF-16 LE"));
	dlg.AddControlItem(IDC_COMBO, 2, _T("UTF-16 BE"));
	dlg.AddControlItem(IDC_COMBO, 3, _T("UTF-8"));
	dlg.AddControlItem(IDC_COMBO, 4, _T("UTF-8 BOM"));
	dlg.SetSelectedControlItem(IDC_COMBO, n_type);
	
	if (IDCANCEL == dlg.DoModal()) {
		return;
	}
	dlg.GetSelectedControlItem(IDC_COMBO, (DWORD&)n_type);
	m_sFile = dlg.GetPathName();
	OnFileSave();
}


void CNodeDlg::OnFileOpen()
{
	/*
	BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
	LPCTSTR lpszDefExt = NULL, 默认扩展名，在输入文件名时自动追加扩展名
	LPCTSTR lpszFileName = NULL, 默认文件名，会显示在输入框中，一般用来定位 "C:\\Windows\\"
	DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 
	LPCTSTR lpszFilter = NULL,
	CWnd* pParentWnd = NULL,
	DWORD dwSize = 0,
	BOOL bVistaStyle = TRUE
	*/
	if (m_edit.GetModify()) {
		if (!Prompt()) {
			return;
		}
	}
	CFileDialog dlg(TRUE, _T("txt"), _T("E:\\"), 0, szFilter);
	INT_PTR ret = dlg.DoModal();
	if (ret == IDCANCEL) {
		return;
	}
	CString str = dlg.GetPathName();
	ReadText(str);
	UpdateTitle();
}


void CNodeDlg::OnFileSave()
{
	if (!SelectFile()) {
		return;
	}
	CFile file;
	if (!file.Open(m_sFile, CFile::modeCreate | CFile::modeWrite)) {
		AfxMessageBox(_T("保存文件失败"));
		return;
	}
	CString str;
	m_edit.GetWindowText(str);
	switch (n_type) {
		case ANSI: {
			char* p = CClient::UTF16LEToANSI(str);
			file.Write(p, strlen(p));
			delete[] p;
		}
			break;
		case UTF16_BE: {
			// char* p = CClient::CStringToPChar(str);
			wchar_t* p = str.GetBuffer();// p的有效期受str影响
			str.ReleaseBuffer();// 因为修改了必须摧毁
			CClient::ConvertBig(reinterpret_cast<char*>(p));
			// CClient::ConvertBig((LPSTR)(LPCTSTR)p); 更节省内存
			str = CString(p);
			WORD w{ 0xFFFE };
			file.Write(&w, sizeof(w));
			file.Write(str, sizeof(TCHAR) * str.GetLength());
		}
			break;
		case UTF16_LE: {
			WORD w{ 0xFEFF };
			file.Write(&w, sizeof(w));
			file.Write(str, sizeof(TCHAR) * str.GetLength());
		}
			break;
		case UTF8: {
			char* p = CClient::UTF16LEToUTF8(str);
			file.Write(p, strlen(p));
			delete[] p;
		}
			break;
		case UTF8BOM: {
			DWORD dw{ 0xBFBBEF };
			file.Write(&dw, sizeof(dw));
			char* p = CClient::UTF16LEToUTF8(str);
			file.Write(p, strlen(p));
			delete[] p;
		}
			break;
	}

	file.Close();// 也可不写析构会执行
	UpdateTitle();
	m_edit.SetModify(FALSE);
}


void CNodeDlg::OnFileSet()
{
	CPageSetupDialog dlg(PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS | PSD_ENABLEPAGEPAINTHOOK);
	dlg.DoModal();
}


void CNodeDlg::OnFilePrint()
{
	CPrintDialog dlg(FALSE);
	dlg.DoModal();
}

// 菜单退出回调
void CNodeDlg::OnFileExit()
{
	if (Prompt()) {
		// EndDialog(IDCANCEL);// 对模式对话框有效，对于非模式对话框只是隐藏
		DestroyWindow();// 用于关闭非模式对话框；并且PostNcDestroy()需要继续回收
	}
}

// 撤销
void CNodeDlg::OnEditUndo()
{
	m_edit.Undo();
}

void CNodeDlg::OnEditCut()
{
	m_edit.Cut();
}

void CNodeDlg::OnEditCopy()
{
	m_edit.Copy();
}

void CNodeDlg::OnEditPaste()
{
	m_edit.Paste();// 粘贴
}

void CNodeDlg::OnEditDel()
{
	m_edit.Clear();
}

// 全选
void CNodeDlg::OnEditSelectAll()
{
	// 设置开始和结束选中位置，-1表示全部
	m_edit.SetSel(0, -1);
}

void CNodeDlg::OnEditGoto()
{
	// 光标所在位置，传参则是第几行的位置
	int n = m_edit.LineIndex();// 行号转位置

	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	int line = m_edit.LineFromChar(nEnd);// 位置转行号
	CGotoDlg dlg;
	dlg.m_nLine = line;// end作为当前行
	dlg.m_nLines = m_edit.GetLineCount();
	if (dlg.DoModal() == IDCANCEL) {
		return;
	}

	int index = m_edit.LineIndex(dlg.m_nLine);// 根据行获取位置，传入-1或默认就是当前行
	m_edit.SetSel(index, index);
}


// 右下角图标点击事件
afx_msg LRESULT CNodeDlg::OnUmNotify(WPARAM wParam, LPARAM lParam)
{
	switch (lParam) {
	case WM_LBUTTONDBLCLK:// 双击
		ShowWindow(SW_SHOWNORMAL);// 显示窗口
		break;
	case WM_RBUTTONDOWN:// 右击
		CMenu menu;
		if (menu.LoadMenu(IDR_MENU)) {
			CMenu* popup = menu.GetSubMenu(0);// 获取第一列
			CPoint cPoint;
			GetCursorPos(&cPoint);
			SetForegroundWindow();
			popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, cPoint.x, cPoint.y, this);
		}
		break;
	}
	return 0;
}

BOOL CNodeDlg::Prompt()
{
	if (m_edit.GetModify()) {
		CString str = m_sFile;
		if (str.IsEmpty()) {
			str = _T("无标题");
		}
		int ret = AfxMessageBox(_T("你想把") + str +_T("更改保存到文件吗？"), MB_YESNOCANCEL);
		if (ret == IDCANCEL) {
			return FALSE;
		}
		if (ret == IDYES) {
			if (!SelectFile()) {
				return FALSE;
			}
		}
	}
	return TRUE;
}

// 更新标题栏文件名
void CNodeDlg::UpdateTitle()
{
	CString str;
	if (m_sFile.IsEmpty()) {
		str = _T("无标题");
	}
	else {
		int n = m_sFile.ReverseFind(_T('\\'));// 反向找
		if (n > 1) {
			str = m_sFile.Mid(n + 1);// n ~ 截取
		}
		else {
			str = _T("无标题");
		}
	}
	str += _T(" - 记事本");
	SetWindowText(str);
}

BOOL CNodeDlg::SelectFile()
{
	if (m_sFile.IsEmpty()) {
		CFileDialog dlg(FALSE, _T("txt"), _T("E:\\"), OFN_OVERWRITEPROMPT, szFilter);// FALSE 另存为
		if (IDCANCEL == dlg.DoModal()) {
			return FALSE;
		}
		m_sFile = dlg.GetPathName();
		OnFileSave();
	}
	return TRUE;
}

// 仅设置父窗口接收文件TRUE，否则消息被拦
void CNodeDlg::OnDropFiles(HDROP hDropInfo)
{
	TCHAR s[MAX_PATH];
	int nCount = DragQueryFile(hDropInfo, 0, s, _countof(s));
	ReadText(s);
	DragFinish(hDropInfo);

	CDialog::OnDropFiles(hDropInfo);
}

void CNodeDlg::ReadText(LPCTSTR sFile)
{
	CFile file;
	if (!file.Open(sFile, CFile::modeRead)) {
		return;
	}
	m_sFile = sFile;
	ULONGLONG nSize = file.GetLength();
	if (nSize > 0) {
		char* p = new char[nSize + 2];
		int n = file.Read(p, nSize);
		p[n] = 0;
		p[n + 1] = 0;// 宽字节的会用到
		ParseText(p);
		delete[] p;
	}
}

void CNodeDlg::ParseText(LPSTR p)
{
	wchar_t* q = nullptr;
	BYTE b1 = *p;
	BYTE b2 = *(p + 1);
	BYTE b3 = *(p + 2);
	
	// UTF-16
	if ((b1 == 0xFE && b2 == 0xFF) || (b1 == 0xFF && b2 == 0xFE)) {
		if ((b1 == 0xFE && b2 == 0xFF)) {// BE 大端
			CClient::ConvertBig(p);
			n_type = UTF16_BE;
		}
		else {
			n_type = UTF16_LE;
		}
		// LE 小端，项目默认支持类型
		m_edit.SetWindowText(reinterpret_cast<wchar_t*>(p+2));
	}
	// UTF-8 BOM
	else if (b1 == 0xEF && b2 == 0xBB && b3 == 0xBF) {
		n_type = UTF8BOM;
		q = CClient::UTF8ToUTF16LE(p + 3);
	}
	// UTF-8
	else if (CClient::CheckUtf8(p)) {
		n_type = UTF8;
		q = CClient::UTF8ToUTF16LE(p);
	}
	// 默认ANSI
	else {
		n_type = ANSI;
		q = CClient::ANSIToUTF16LE(p);
	}
	if (q != nullptr) {
		m_edit.SetWindowText(q);
		delete[] q;
	}
}

CString CNodeDlg::GetSelText()
{
	CString str;
	m_edit.GetWindowText(str);
	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	if (nEnd <= nStart) {
		return str;
	}
	return str.Mid(nStart, nEnd-nStart);
}


void CNodeDlg::OnEditSearch()
{
	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	CString str;
	m_edit.GetWindowText(str);
	str = str.Mid(nStart, nEnd - nStart);
	str = _T("https://www.baidu.com/s?wd=") + str;
	ShellExecute(NULL, _T("open"), str, NULL, NULL, SW_SHOWNORMAL);
}


void CNodeDlg::OnEditFind()
{
	// CFindReplaceDialog 重写了虚函数 PostNcDestroy() 加了delete this 所以需要new，也可以派生类再重写掉
	// if (IsWindow(m_pReplaceDlg->GetSafeHwnd()) 这种写法更简单
	if (m_pReplaceDlg != nullptr && IsWindow(m_pReplaceDlg->m_hWnd)) {// 已创建
		m_pReplaceDlg->DestroyWindow();// 非模式对话框关闭；当前函数调用会触发CFindReplaceDialog  PostNcDestroy() 中delete，所以不需要delete
	}
	m_pReplaceDlg = new CFindReplaceDialog;
	// FR_MATCHCASE 区分大小写  FR_WHOLEWORD 全字匹配
	m_pReplaceDlg->Create(TRUE, GetSelText(), NULL, FR_MATCHCASE | FR_WHOLEWORD);// TRUE 查找 FALSE替换
	m_pReplaceDlg->ShowWindow(SW_SHOW);
}


void CNodeDlg::OnEditNext()
{
	// TODO: 在此添加命令处理程序代码
}


void CNodeDlg::OnEditPrev()
{
	// TODO: 在此添加命令处理程序代码
}


void CNodeDlg::OnEditReplace()
{
	if (m_pReplaceDlg != nullptr && IsWindow(m_pReplaceDlg->m_hWnd)) {// 已创建
		m_pReplaceDlg->DestroyWindow();// 非模式对话框关闭；当前函数调用会触发CFindReplaceDialog  PostNcDestroy() 中delete，所以不需要delete
	}
	m_pReplaceDlg = new CFindReplaceDialog;
	// FR_MATCHCASE 区分大小写  FR_WHOLEWORD 全字匹配
	m_pReplaceDlg->Create(FALSE, GetSelText(), NULL, 0);// TRUE 查找 FALSE替换
	m_pReplaceDlg->ShowWindow(SW_SHOW);
}


void CNodeDlg::OnEditDate()
{
	CTime time = CTime::GetCurrentTime();
	CString str;
	str.Format(_T("%02d:%02d %d/%d/%d"), time.GetHour(), time.GetMinute(), time.GetYear(),
		time.GetMinute(), time.GetDay());
	m_edit.ReplaceSel(str, TRUE);// TRUE 按ctrl + z可以撤销
	// 快捷键 资源 -> 添加Accelerator -> 修饰符就是ctrl需要多个按键的情况

}


BOOL CNodeDlg::PreTranslateMessage(MSG* pMsg)
{
	// 预先 翻译 消息
	// 很多控件消息被控件劫走，这里先于控件
	if (m_hAccel) {
		if (TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) {
			return TRUE;
		}
	}

	return CDialog::PreTranslateMessage(pMsg);
}

/*
可以使用结构体生成默认
LOGFONT lf{21};// 给第一个变量赋值
lf.lfWeight = 400; // 700 粗体
lf.lfCharSet = GB2312_CHARSET;// 编码
_tcscpy_s(lf.lfFaceName, _countof(lf.lfFaceName), _T("楷体"));
CFont m_font;// 得全局
m_font.DeleteObject();// 销毁句柄
m_font.CreateFontIndirect(&lf);// 创建句柄
m_edit.SetFont(&m_font);
*/
void CNodeDlg::OnFormatFont()
{
	LOGFONT lf;
	// 获取当前字体信息
	CFont* pFont = m_edit.GetFont();
	pFont->GetLogFont(&lf);

	CFontDialog dlg(&lf);
	if (dlg.DoModal() == IDCANCEL) {
		return;
	}
	
	dlg.GetCurrentFont(&lf);// 从对话框中获取用户设置的字体信息
	m_font.DeleteObject();// 删除CFont中的字体句柄
	m_font.CreateFontIndirect(&lf);// 生成CFont中的字体句柄
	m_edit.SetFont(&m_font);// 设置编辑框字体

	// 写入注册表或配置文件，由入口配置而定
	theApp.WriteProfileBinary(_T("SETTING"), _T("FONT"), (LPBYTE)&lf, sizeof(LOGFONT));
}


void CNodeDlg::OnFormatText()
{
	CColorDialog dlg(m_clText, CC_FULLOPEN);
	if (dlg.DoModal() == IDCANCEL) {
		return;
	}
	m_clText = dlg.GetColor();
	m_brush.DeleteObject();
	m_brush.CreateSolidBrush(m_clBlack);
	theApp.WriteProfileInt(_T("SETTING"), _T("TEXT_COLOR"), m_clText);
}


void CNodeDlg::OnFormatBack()
{
	CColorDialog dlg(m_clBlack, CC_FULLOPEN);
	if (dlg.DoModal() == IDCANCEL) {
		return;
	}
	if (dlg.GetColor() == m_clBlack) {
		return;
	}
	m_clBlack = dlg.GetColor();
	m_brush.DeleteObject();
	m_brush.CreateSolidBrush(m_clBlack);

	// 写入配置或注册表
	// 	m_clText = theApp.GetProfileInt(_T("SETTING"), _T("TEXT_COLOR"), 0x000000);
	// m_clBlack = theApp.GetProfileInt(_T("SETTING"), _T("BACK_COLOR"), 0xffffff);
	theApp.WriteProfileInt(_T("SETTING"), _T("BACK_COLOR"), m_clBlack);
}

LRESULT CNodeDlg::OnFindReplace(WPARAM wParam, LPARAM lParam)
{
	m_pReplaceDlg->MatchWholeWord();// 全字匹配
	m_pReplaceDlg->MatchCase();// 区分大小写
	if (m_pReplaceDlg->IsTerminating()) {
		//AfxMessageBox(_T("取消"));
	}
	if (m_pReplaceDlg->FindNext()) {
		//AfxMessageBox(_T("查找下一个"));
		if (m_pReplaceDlg->SearchDown()) {
			SearchDown();
		}
		else {
			SearchUp();
		}
	}
	if (m_pReplaceDlg->ReplaceCurrent()) {
		//AfxMessageBox(_T("替换"));
		ReplaceCurrent();
	}
	if (m_pReplaceDlg->ReplaceAll()) {
		//AfxMessageBox(_T("全部替换"));
		ReplaceAll();
	}
	return 0;
}

void CNodeDlg::SearchDown()
{
	if (!IsWindow(m_pReplaceDlg->GetSafeHwnd())) {// 窗口句柄已销毁
		return;
	}
	CString str = m_pReplaceDlg->GetFindString();
	CString sText;
	m_edit.GetWindowText(sText);
	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	if (!m_pReplaceDlg->MatchCase()) {// 不区分大小写
		str.MakeLower();// 转小写
		sText.MakeLower();
	}
	int n = sText.Find(str, nEnd);// 查找字符串和开始位置
	if (n < 0) {
		AfxMessageBox(_T("找不到：") + str);
		return;
	}
	m_edit.SetSel(n, n + str.GetLength());// 设置选中
}

void CNodeDlg::SearchUp()
{
	if (!IsWindow(m_pReplaceDlg->GetSafeHwnd())) {// 窗口句柄已销毁
		return;
	}
	CString str = m_pReplaceDlg->GetFindString();
	CString sText;
	m_edit.GetWindowText(sText);
	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	// 反转
	str.MakeReverse();
	sText.MakeReverse();
	int n = sText.Find(str, sText.GetLength() - nStart);
	if (n < 0) {
		AfxMessageBox(_T("找不到：") + str);
		return;
	}
	int newEnd = sText.GetLength() - n;
	int newStart = newEnd - str.GetLength();
	m_edit.SetSel(newStart, newEnd);// 设置选中
}

void CNodeDlg::ReplaceAll()
{
	CString sText, sOld, sNew;
	sOld = m_pReplaceDlg->GetFindString();
	sNew = m_pReplaceDlg->GetReplaceString();
	m_edit.GetWindowText(sText);
	sText.Replace(sOld, sNew);
	int nStart, nEnd;
	m_edit.GetSel(nStart, nEnd);
	m_edit.SetWindowText(sText);
	m_edit.SetSel(nStart, nEnd);
}

void CNodeDlg::ReplaceCurrent()
{
	// m_edit.ReplaceSel();// 替换选择的内容
}




// WM_CTLCOLOR消息回调
HBRUSH CNodeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

	if (pWnd->GetDlgCtrlID() == IDC_EDIT) {// 编辑框句柄ID
		pDC->SetTextColor(m_clText);// 文字色
		pDC->SetBkColor(m_clBlack);// 文字区域背景色
		return m_brush;
	}

	// TODO:  如果默认的不是所需画笔，则返回另一个画笔
	return hbr;
}


void CNodeDlg::OnFormatWrap()
{
	// 自动换行
	DWORD dwStyle = m_edit.GetStyle();
	DWORD dwStyleEx = m_edit.GetExStyle();
	CString str;
	m_edit.GetWindowText(str);
	CRect rect;
	GetClientRect(rect);
	m_edit.DestroyWindow();
	// 1011 (0010 0001) -> 1011 ~0011 -> 1011 1100 -> 1011 & 1100 -> 1000
	if (dwStyle & WS_HSCROLL) {
		dwStyle &= (~(ES_AUTOVSCROLL | WS_HSCROLL));// 移除属性
	}
	else {
		dwStyle |= ES_AUTOVSCROLL | WS_HSCROLL;// 添加属性
	}
	// Auto HScroll： FALSE  否则无效
	m_edit.CreateEx(dwStyleEx, _T("Edit"), str, dwStyle, rect, this, IDC_EDIT);
	m_edit.SetFont(&m_font);
}
